<script lang="jsx">
import { defineComponent } from 'vue'
import {
  ElInput,
  ElSelect,
  ElOption,
  ElDatePicker,
  ElTimePicker,
  ElInputNumber,
  ElSwitch,
  ElRadioGroup,
  ElRadioButton,
  ElCheckboxGroup,
  ElCheckbox,
  ElCascader,
  ElSlider,
  ElRate,
  ElColorPicker,
  ElTransfer,
  ElAutocomplete,
  ElTimeSelect,
  ElRadio,
  ElCheckboxButton,
  ElColorPickerPanel,
  ElDatePickerPanel,
  ElInputTag,
  ElMention,
  ElSelectV2,
  ElTreeSelect,
  ElUpload,
} from 'element-plus'

// 组件名称映射，支持 kebab-case 和 PascalCase 两种格式
const componentMap = {
  'el-autocomplete': ElAutocomplete, // 自动补全组件
  'el-cascader': ElCascader, // 级联选择器
  // 多选组件
  'el-checkbox-group': ElCheckboxGroup,
  'el-checkbox': ElCheckbox,
  // 颜色选择器
  'el-color-picker-panel': ElColorPickerPanel,
  'el-color-picker': ElColorPicker,
  // 日期时间组件
  'el-date-picker-panel': ElDatePickerPanel,
  'el-date-picker': ElDatePicker,
  'el-time-picker': ElTimePicker,
  'el-time-select': ElTimeSelect,
  'el-input': ElInput, // 基础输入组件
  'el-input-number': ElInputNumber, // 数字输入组件
  'el-input-tag': ElInputTag, // 标签输入框
  'el-mention': ElMention, // 提及
  // 单选组件
  'el-radio': ElRadio,
  'el-radio-group': ElRadioGroup,
  'el-radio-button': ElRadioButton,
  'el-rate': ElRate, // 评分组件
  'el-select': ElSelect, // 选择器组件
  'el-option': ElOption,
  'el-select-v2': ElSelectV2, // 虚拟化选择器
  'el-slider': ElSlider, // 滑块组件
  'el-switch': ElSwitch, // 开关组件
  'el-transfer': ElTransfer, // 穿梭框组件
  'el-tree-select': ElTreeSelect, // 树形选择器
  'el-upload': ElUpload,
}

export default defineComponent({
  name: 'FormValue',
  props: {
    modelValue: {
      type: [String, Number, Boolean, Array, Object],
      default: null,
    },
    column: {
      type: Object,
      default: () => ({
        valueType: 'el-input', // 组件名称，如 'el-input', 'el-select' 等
        props: {}, // 组件属性
        emits: {}, // 组件事件监听器
        options: null, // 一些下拉选项
        optionsType: null, // 操作类型 例如el-radio-group 下 有radio和radioButton 具体哪一种类型
        render: null, // 自定义渲染函数
        slots: {}, // 自定义插槽 如果是渲染函数 那么就直接渲染，   是字符串那就为插槽名
      }),
    },
  },
  emits: ['update:modelValue'],
  setup(props, context) {
    const { slots, emit } = context
    /**
     * 根据类型获取对应的组件
     * @param valueType 组件类型
     * @param optionsType 选项类型
     */
    const getOptionComp = (valueType, optionsType) => {
      switch (valueType) {
        case 'el-select':
          return ElOption
        case 'el-checkbox-group':
          if (optionsType === 'checkboxButton') {
            return ElCheckboxButton
          } else {
            return ElCheckbox
          }
        case 'el-radio-group':
          if (optionsType === 'radioButton') {
            return ElRadioButton
          } else {
            return ElRadio
          }
        default:
          return null
      }
    }

    /**
     * 渲染选项 例如el-select-option、el-checkbox-group的el-checkbox。。。。等等
     * @param valueType 组件类型
     * @param options 选项列表
     * @param optionsType 选项类型 例如el-radio-group 下 有radio和radioButton 具体哪一种类型
     * @param optionsSlots 插槽配置
     */
    const renderOptions = (valueType, options, optionsType, optionsSlots) => {
      if (!options || !Array.isArray(options)) return null

      const Component = getOptionComp(valueType, optionsType)

      if (!Component) {
        return null
      }
      return options.map((option) => {
        const { label, value, ...optionProps } = option
        return (
          <Component key={value} label={label} value={value} {...optionProps}>
            {renderSlots(optionsSlots, slots, option)}
          </Component>
        )
      })
    }

    /**
     * 根据插槽配置渲染插槽
     * @param slotsConfig 插槽配置
     * @param slots 父组件插槽
     * @param otherScope 其他参数
     */
    const renderSlots = (slotsConfig, slots, otherScope) => {
      if (!slotsConfig) return {}

      const scopedSlots = {}

      Object.keys(slotsConfig).forEach((slotName) => {
        const slotValue = slotsConfig[slotName]
        // 将 scope 和 arg 合并为一个参数对象传递

        if (typeof slotValue === 'function') {
          // 如果是渲染函数，直接执行
          scopedSlots[slotName] = (scope) => {
            return slotValue({ ...scope, ...otherScope })
          }
        } else if (typeof slotValue === 'string') {
          // 如果是字符串，表示插槽名，从父组件插槽中获取
          scopedSlots[slotName] = (scope) => {
            return slots[slotValue]?.({ ...scope, ...otherScope })
          }
        }
      })

      return scopedSlots
    }

    /**
     * 绑定值的更改事件，触发父组件的 update:modelValue 事件 具体参考v-model实现原理
     */
    const changeValue = (val) => {
      emit('update:modelValue', val)
    }

    return () => {
      const {
        valueType = 'el-input',
        emits: columnEmits = {},
        props: componentProps = {},
        optionsType,
        optionsSlots,
        options,
        render,
        slots: slotsConfig,
      } = props.column || {}

      // 如果提供了 render 函数，优先使用自定义渲染
      if (render && typeof render === 'function') {
        return render(props, context, changeValue)
      } else if (typeof render === 'string') {
        return slots[render]?.({ props, context, changeValue })
      }

      // 处理事件绑定 - 转换事件名格式
      const eventHandlers = Object.keys(columnEmits).reduce((events, event) => {
        // 将事件名转换为 JSX 格式 (change -> onChange)
        const jsxEventName = `on${event.charAt(0).toUpperCase() + event.slice(1)}`
        events[jsxEventName] = columnEmits[event]
        return events
      }, {})

      const Component = componentMap[valueType]
      if (!Component) {
        console.warn(`未找到组件: ${valueType}`)
        return null
      }

      return (
        <Component
          {...componentProps}
          {...eventHandlers}
          v-slots={slotsConfig ? renderSlots(slotsConfig, slots) : slots}
          modelValue={props.modelValue}
          onUpdate:modelValue={changeValue}
        >
          {renderOptions(valueType, options, optionsType, optionsSlots)}
        </Component>
      )
    }
  },
})
</script>

<style scoped lang="scss"></style>
